<?php
/**
 * MVC运行控制类
 * 
 * $Id: mvc.php 127 2010-09-05 15:32:42Z Administrator $
 * $Revision: 127 $
 * $Author: Administrator $
 * $Date: 2010-09-05 23:32:42 +0800 (星期日, 05 九月 2010) $
 * 实现MVC控制结构，可以定义模块，模块运作，由那个控
 * 制器进行运行，内置安装程序依靠些程序运行。
 * 
 * @author glzaboy<glzaboy@163.com>
 * @package fastlib
 * @subpackage classes
 * @copyright 2005-2010 (c) glzaboy
 */
if (! defined ( '__FASTLIB__' )) {
	if (__DEBUG__) {
		die ( sprintf ( 'Forbidden 403 at file %s on line %d', __FILE__, __LINE__ ) );
	} else {
		die ( 'Forbidden 403' );
	}
}
/**
 * 简易MVC控制类
 * 
 * 本模块会自动生成几个常量
 * __FASTMVC_ROOT__　控制器文件名
 * __FASTMVC_FACTOR__
 * __FASTMVC_M__ 传递模块使用的变量名,本变量来自GET
 * __FASTMVC_MV__　使用的模块名
 * __FASTMVC_ACT__ 传递动作使用的变量名，本变量来自GET
 * __FASTMVC_ACTV__　要操作的动作
 * 
 * 实现一个简单的MVC控制结构
 */
class mvc {
	/**
	 * 默认模块
	 *
	 * @var string
	 */
	private $defmodule = null;
	/**
	 * 默认动作
	 *
	 * @var string
	 */
	private $defaction = null;
	/**
	 * 模块因数
	 *
	 * @var string
	 */
	private $factor = null;
	/**
	 * 模块代码目录
	 *
	 * @var string
	 */
	private $mdir = null;
	/**
	 * mvc 初始设置
	 *
	 * factor参数的主要作用是区分不同的控制器
	 * 
	 * @param string $factor　模块因数,主要用于区分控制器
	 * @param string $moduleDir 模块目录，相对于主控制模块
	 * @param string $defmodule 默认模块
	 * @param string $defaction 默认动作
	 * @return mvc
	 */
	public function __construct($factor = null, $moduleDir = 'source', $defmodule = "index", $defaction = 'home') {
		$this->defmodule = is_string ( $defmodule ) ? $defmodule : 'index';
		$this->defaction = is_string ( $defaction ) ? $defaction : 'home';
		$this->factor = is_string ( $factor ) ? $factor : 'mvc';
		$this->mdir = is_string ( $moduleDir ) ? $moduleDir : 'source';
		/**
		 * 模块代码目录
		 *
		 */
		define ( '__FASTMVC_FACTOR__', $this->factor );
	}
	/**
	 * mvc运行
	 *
	 * @param string $module 使用的get中的模块名称
	 * @param string $action 使用的get中的模块动作名称
	 * @param bool $fullpath 路由使用完整路径
	 */
	public function run($module = 'm', $action = 'ac', $fullpath = false) {
		if (! is_string ( $module )) {
			$module = 'm';
		}
		if (! is_string ( $action )) {
			$action = 'ac';
		}
		$modules = $this->modulesStore ( $this->factor, 'get' );
		$m = (isset ( $_GET [$module] ) && is_string ( $_GET [$module] )) ? $_GET [$module] : $this->defmodule;
		$ac = (isset ( $_GET [$action] ) && is_string ( $_GET [$action] )) ? $_GET [$action] : (isset ( $modules [$m] [md5 ( $m . 'default' )] ) ? $modules [$m] [md5 ( $m . 'default' )] : $this->defaction);
		/**
		 * 控制器文件名
		 *
		 */
		define ( '__FASTMVC_ROOT__', $fullpath ? $_SERVER ['PHP_SELF'] : array_pop ( explode ( '/', $_SERVER ['PHP_SELF'] ) ) );
		/**
		 * 传递模块使用的变量名,本变量来自GET
		 *
		 */
		define ( '__FASTMVC_M__', $module );
		/**
		 * 传递动作使用的变量名，本变量来自GET
		 *
		 */
		define ( '__FASTMVC_ACT__', $action );
		/**
		 * 使用的模块名
		 *
		 */
		define ( '__FASTMVC_MV__', $m );
		/**
		 * 要操作的动作
		 *
		 */
		define ( '__FASTMVC_ACTV__', $ac );
		if (isset ( $modules [$m] [md5 ( $m . 'disabled' )] )) {
			setHeader ( 'http', '403 Forbidden' );
		}
		unset ( $modules [$m] [md5 ( $m . 'default' )], $modules [$m] [md5 ( $m . 'disabled' )] ); //清除模块名称和模块默认操作
		if ($ac === 'lock') {
			$this->modulesStore ( null, 'lock' );
			loadClass ( 'message', __FILE__, __LINE__ );
			new message ( __ ( 'System moduel lock Sucess,if you want change module,please unlock module.' ), array ('value' => __ ( 'back' ), 'key' => 'b' ), __ ( 'mvc moudle' ), 0 );
			exit ( 0 );
		}
		if (in_array ( $ac, array ('install', 'remove', 'enable', 'disable' ) ) && $this->factor == 'install' && (isset ( $m ) && $m !== '')) {
			if ($this->modulesStore ( null, 'getlock' )) {
				loadClass ( 'message', __FILE__, __LINE__ );
				new message ( __ ( 'System lock moduel,if you want change module,please unlock module.' ), array ('value' => __ ( 'back' ), 'key' => 'b' ), __ ( 'mvc moudle' ), 0 );
				exit ( 1 );
			}
			require $this->mdir . '/' . __FASTMVC_MV__ . '.php';
		} elseif (isset ( $modules [$m] ) && in_array ( $ac, $modules [$m] )) {
			if (is_file ( $this->mdir . '/' . __FASTMVC_MV__ . '.php' )) {
				require $this->mdir . '/' . __FASTMVC_MV__ . '.php';
			} else {
				setHeader ( 'http', '404 File not fonud' );
			}
		} else {
			setHeader ( 'http', '404 File not fonud' );
		}
		return true;
	}
	/**
	 * 检测模块是否已经安装
	 * 
	 * 如果有动作名，那么将测试模块中是否存在指定动作
	 *
	 * @param string $module 模块名称
	 * @param string $action 动作名称 
	 * @return bool $fullpath 路由使用完整路径
	 */
	public function exists($module, $action = null, $factor = null) {
		if (! is_string ( $module )) {
			return false;
		}
		if ($factor == null) {
			$modules = $this->modulesStore ( $this->factor, 'get' );
		} else {
			$modules = $this->modulesStore ( $factor, 'get' );
		}
		unset ( $modules [$module] [md5 ( $module . 'default' )] ); //清除模块名称和模块默认操作
		if ($action === null) {
			return isset ( $modules [$module] );
		} else {
			return isset ( $modules [$module] ) && in_array ( $action, $modules [$module] );
		}
	}
	/**
	 * 检测模块是否可以调用
	 *
	 * @param string $module
	 * @return bool 是否可以调用
	 */
	public function enable($module, $factor = null) {
		if ($factor == null) {
			if ($this->exists ( $module )) {
				return ! $this->exists ( $module, md5 ( $module . 'disabled' ) );
			} else {
				return false;
			}
		} else {
			if ($this->exists ( $module, null, $factor )) {
				return ! $this->exists ( $module, md5 ( $module . 'disabled' ), $factor );
			} else {
				return false;
			}
		}
	}
	/**
	 * 存储读取模块信息
	 * 
	 * 本函数可以读取，设置，锁定，解锁，取锁状态信息
	 * 参数分别为
	 * install 安装
	 * remove 移除
	 * lock 锁定
	 * unlock 解锁
	 * getlock 取得锁状态
	 * get 取模块信息
	 *
	 * @param string $factor 模块因数
	 * @param string $act 操作类型
	 * @param string $module
	 * @param array $actions
	 * @param string $defaction 默认动作，只到本$factor起作用，如果控制器指定默认动作，在注册的时候也指定以这里为准
	 * @return mixed 读取，设置，锁定，解锁，取锁状态信息
	 */
	public function modulesStore($factor, $act = 'get', $module = null, $actions = array(), $defaction = null) {
		$dir = getSiteCurrent ( true ) . 'data';
		touchdir ( $dir );
		$http403 = '<?php' . PHP_EOL . ' die("HTTP 403");?>';
		if (! file_exists ( $dir . '/mvc.php' )) {
			file_put_contents ( $dir . '/mvc.php', $http403 . serialize ( array () ) );
		}
		$modules = unserialize ( substr ( file_get_contents ( $dir . '/mvc.php' ), strlen ( $http403 ) ) );
		switch (strtolower ( $act )) {
			case 'install' :
				if ($factor == null) {
					$factor = 'mvc';
				}
				$modules [$factor] [$module] = $actions;
				$modules [$factor] [$module] [md5 ( $module . 'default' )] = $defaction ? $defaction : null;
				if (file_put_contents ( $dir . '/mvc.php', $http403 . serialize ( $modules ) )) {
					return true;
				} else {
					return false;
				}
				break;
			case 'disable' :
				if ($factor == null) {
					$factor = 'mvc';
				}
				$modules [$factor] [$module] = $actions;
				$modules [$factor] [$module] [md5 ( $module . 'default' )] = $defaction ? $defaction : null;
				$modules [$factor] [$module] [md5 ( $module . 'disabled' )] = true;
				if (file_put_contents ( $dir . '/mvc.php', $http403 . serialize ( $modules ) )) {
					return true;
				} else {
					return false;
				}
				break;
			case 'enable' :
				if ($factor == null) {
					$factor = 'mvc';
				}
				$modules [$factor] [$module] = $actions;
				$modules [$factor] [$module] [md5 ( $module . 'default' )] = $defaction ? $defaction : null;
				unset ( $modules [$factor] [$module] [md5 ( $module . 'disabled' )] );
				if (file_put_contents ( $dir . '/mvc.php', $http403 . serialize ( $modules ) )) {
					return true;
				} else {
					return false;
				}
				break;
			case 'remove' :
				if ($factor == null) {
					$factor = 'mvc';
				}
				unset ( $modules [$factor] [$module] );
				if (! count ( $modules [$factor] )) {
					unset ( $modules [$factor] );
				}
				if (file_put_contents ( $dir . '/mvc.php', $http403 . serialize ( $modules ) )) {
					return true;
				} else {
					return false;
				}
				break;
			case 'lock' :
				if (touch ( $dir . '/mvc.lock' )) {
					return true;
				} else {
					return false;
				}
				break;
			case 'unlock' :
				if (unlink ( $dir . '/mvc.lock' )) {
					return true;
				} else {
					return false;
				}
				break;
			case 'getlock' :
				if (file_exists ( $dir . '/mvc.lock' )) {
					return true;
				} else {
					return false;
				}
				break;
			case 'get' :
			default :
				$modules = isset ( $modules [$factor] ) ? $modules [$factor] : null;
				return $modules;
				break;
		}
		return null;
	}
	/**
	 * 改写site.table.php配置文件
	 * 
	 * 本功能只作为mvc模块附加功能
	 *
	 * @param string $dt 数据表配置
	 * @param string $act 操作(install/remove)
	 * @return bool 操作结果
	 */
	function writeTable($dt, $act = 'install') {
		if (! defined ( '__SITE__' )) {
			return false;
		}
		if (file_exists ( getSiteCurrent ( true ) . 'data/site.table.php' )) {
			if (! is_writable ( getSiteCurrent ( true ) . 'data/site.table.php' )) {
				return false;
			}
			$dtContent = file_get_contents ( getSiteCurrent ( true ) . 'data/site.table.php' );
		} else {
			touchdir ( getSiteCurrent ( true ) . 'data' );
			$dtContent = <<<DT
<?php
if (! defined('__FASTLIB__')) {
    header("HTTP/1.1 301 Moved Permanently");
    header("Last-Modified:" . date('r'));
    header("Expires: " . date('r', time() + 86400));
    exit("HTTP/1.1 301 Moved Permanently ");
}
DT;
		}
		switch (strtolower ( $act )) {
			case 'install' :
				if (! strpos ( $dtContent, $dt )) {
					$dtContent .= PHP_EOL . trim ( $dt );
					file_put_contents ( getSiteCurrent ( true ) . 'data/site.table.php', trim ( $dtContent ) );
				}
				break;
			case 'remove' :
				if (strpos ( $dtContent, $dt )) {
					$dtContent = strtr ( $dtContent, array (PHP_EOL . $dt => '' ) );
					file_put_contents ( getSiteCurrent ( true ) . 'data/site.table.php', trim ( $dtContent ) );
				}
				break;
		}
		return true;
	}
	/**
	 * URLRewrite生成URL规则
	 *
	 * 规则字串中的%ac%,%m%,%mGet%,%aGET%,%control%,%QUERY_STRING%
	 * 分别被替换成$ac,$m,$mGet,$aGet,$control,$QUERY_STRING
	 * $argv可以是字符串或是关联数组 
	 * 
	 * @param mixed $agrv 附加参数
	 * @param string $ac 模块动作
	 * @param string $m 模块名
	 * @param string $mGet 通过GET传模块名的GET名
	 * @param string $aGet 通过GET传动作的GET名
	 * @param string $control 控制脚本名
	 * @return string改写好的URL规则
	 */
	public function rewrite($agrv = '', $ac = __FASTMVC_ACTV__, $m = __FASTMVC_MV__, $mGet = __FASTMVC_M__, $aGet = __FASTMVC_ACT__, $control = __FASTMVC_ROOT__) {
		global $flibcfg;
		$rewriteRule = isset ( $flibcfg ['rewriteRule'] ) ? $flibcfg ['rewriteRule'] : '';
		if ($rewriteRule === '') {
			$rewriteRule = $control . '?' . http_build_query ( array ($mGet => $m, $aGet => $ac ) );
			if (is_string ( $agrv ) && $agrv != '') {
				$rewriteRule .= '&amp;' . strtr ( $agrv, array ('&' => '&amp;' ) );
			} elseif (is_array ( $agrv ) && count ( $agrv )) {
				$rewriteRule .= '&amp;' . http_build_query ( $agrv );
			}
		} else {
			if (is_string ( $agrv ) && $agrv != '') {
				$rewriteagrv = strtr ( $agrv, array ('&' => '&amp;' ) );
			} elseif (is_array ( $agrv ) && count ( $agrv )) {
				$rewriteagrv = http_build_query ( $agrv );
			} else {
				$rewriteagrv = '';
			}
			$rewriteRule = strtr ( $rewriteRule, array ('%ac%' => $ac, '%m%' => $m, '%mGet%' => $mGet, '%aGet%' => $aGet, '%control%' => substr ( $control, 0, strrpos ( $control, '.' ) ), '%QUERY_STRING%' => $rewriteagrv ) );
		}
		return $rewriteRule;
	}
	/**
	 * 返回本模块信息
	 *
	 * @return string
	 */
	public function printInfo() {
		$version = '$Revision: 127 $';
		$moudle = __CLASS__;
		$return = '';
		$return .= startTable ();
		$return .= printRow ( array (array ('class' => 'h', 'content' => '<center>' . $moudle . '</center>', 'colspan' => '2' ) ) );
		$return .= printRow ( array (array ('class' => 'e', 'content' => 'author' ), array ('class' => 'v', 'content' => 'glzaboy' ) ) );
		$return .= printRow ( array (array ('class' => 'e', 'content' => 'version' ), array ('class' => 'v', 'content' => $version ) ) );
		$return .= printRow ( array (array ('class' => 'e', 'content' => 'URL rewrite' ), array ('class' => 'v', 'content' => 'yes' ) ) );
		$return .= printRow ( array (array ('class' => 'e', 'content' => 'module store support' ), array ('class' => 'v', 'content' => 'yes' ) ) );
		$return .= printRow ( array (array ('class' => 'e', 'content' => 'module & action exists test support' ), array ('class' => 'v', 'content' => 'yes' ) ) );
		$return .= endTable ();
		return $return;
	}
}